﻿using OpenTK.Graphics.OpenGL4;
using OpenTK;
using System.Collections.Generic;
using Painter3D.RenderSys.RenderObject;
using System;

namespace Painter3D.RenderSys.DebugDrawer
{
    class DebugDrawer : IDisposable
    {
        public static DebugDrawer instance;
        private List<LineStruct> lines;
        private Material material;
        private VertexData data;

        public DebugDrawer(int maxCount)
        {
            material = new Material(ShaderManager.Find("VertexColor.glsl"));
            lines = new List<LineStruct>(maxCount);
            data = new ArrayVertexData(new ShaderInfo.VertexRequestTagEnum[]{
              ShaderInfo.VertexRequestTagEnum.Position,
              ShaderInfo.VertexRequestTagEnum.Color
            }, VertexData.EmptyBuffer(maxCount * 9),
            PrimitiveType.Lines,
            BufferUsageHint.StreamDraw
            );
        }

        struct LineStruct
        {
            readonly Vector3 start;
            readonly Vector3 end;
            readonly Vector3 color;

            public LineStruct(Vector3 start, Vector3 end, Vector3 color)
            {
                this.start = start;
                this.end = end;
                this.color = color;
            }

            public float[] GenerateVertexData()
            {
                float[] buffer = new float[12];

                buffer[0] = start.X;
                buffer[1] = start.Y;
                buffer[2] = start.Z;
                buffer[3] = color.X;
                buffer[4] = color.Y;
                buffer[5] = color.Z;

                buffer[6] = end.X;
                buffer[7] = end.Y;
                buffer[8] = end.Z;
                buffer[9] = color.X;
                buffer[10] = color.Y;
                buffer[11] = color.Z;

                return buffer;
            }
        }

        protected float[] GenerateDataBuffer()
        {
            int index = 0;
            float[] buffer = new float[lines.Count * 12];
            foreach (var line in lines)
            {
                float[] data = line.GenerateVertexData();
                foreach (var value in data)
                {
                    buffer[index] = value;
                    index++;
                }
            }
            return buffer;
        }

        /// <summary>
        /// 绘制一条线段,你需要在每个渲染循环都调用它
        /// </summary>
        /// <param name="start">起点</param>
        /// <param name="end">终点</param>
        /// <param name="color">线段颜色</param>
        public void drawLine(Vector3 start, Vector3 end, Vector3 color)
        {
            lines.Add(new LineStruct(start, end, color));
        }

        /// <summary>
        /// 绘制包围盒
        /// </summary>
        /// <param name="box">包围盒数据</param>
        /// <param name="color">包围盒颜色</param>
        /// <param name="matrix">世界空间矩阵</param>
        public void DrawBoundBox(BoundBox box, Vector3 color, Matrix4 matrix)
        {
            Vector3[] vert = new Vector3[8];
            for (uint i = 0; i < 8; i++)
            {
                vert[i].X = (i & (uint)1) != (uint)0 ? box.Low.X : box.High.X;
                vert[i].Y = (i & (uint)2) != (uint)0 ? box.Low.Y : box.High.Y;
                vert[i].Z = (i & (uint)4) != (uint)0 ? box.Low.Z : box.High.Z;
                vert[i] = new Vector3(new Vector4(vert[i], 1) * matrix);
            }
            drawLine(vert[0], vert[1], color);
            drawLine(vert[2], vert[3], color);
            drawLine(vert[0], vert[2], color);
            drawLine(vert[1], vert[3], color);
            drawLine(vert[4], vert[5], color);
            drawLine(vert[6], vert[7], color);
            drawLine(vert[4], vert[6], color);
            drawLine(vert[5], vert[7], color);
            drawLine(vert[0], vert[4], color);
            drawLine(vert[1], vert[5], color);
            drawLine(vert[2], vert[6], color);
            drawLine(vert[3], vert[7], color);
        }

        /// <summary>
        /// 绘制该render组件下的包围盒数据
        /// </summary>
        /// <param name="render">渲染组件</param>
        public void DrawBoundBox(Render render, Vector3 color)
        {
            DrawBoundBox(render.vertexData.boundBox, color, render.Transform.GetGlobalMat());
        }

        public void DrawTransformTranslateMarker(Transform transform)
        {
            
        }
        public void DrawTransformRotateMarker(Transform transform)
        {

        }
        public void DrawTransformScaleMarker(Transform transform)
        {

        }

        public void DrawOut()
        {
            GL.Disable(EnableCap.DepthTest);
            GL.LineWidth(3);
            Camera.scenceMainCamera.ApplyViewRect();
            RenderPiple.SetUPUniformBuffer(Camera.scenceMainCamera);
            data.Reload(GenerateDataBuffer());
            Render.RenderOut(data, material, Matrix4.Identity);
            lines.Clear();
        }

        static public void Init(int max)
        {
            instance = new DebugDrawer(max);
        }

        #region Dispose

        /// <summary>
        /// 释放对象在显存申请的空间
        /// </summary>
        /// 
        public void Dispose()
        {
            data.Dispose();
            lines.Clear();
            material = null;
            GC.SuppressFinalize(this);
        }
        #endregion
    }
}
